package com.paziy.jan.matrix;

import com.paziy.jan.fraction.*;

/**
 * Created with IntelliJ IDEA.
 * User: paziy
 * Date: 12.10.12
 * Time: 17:25
 * To change this template use File | Settings | File Templates.
 */
public class Operations {

    public static Matrix sum(Matrix a, Matrix b) {
        Matrix result;

        if(a.columnsCount == b.columnsCount && a.rowsCount == b.rowsCount) {

            result = new Matrix(a.rowsCount, a.columnsCount);

            for(int row = 0; row < result.rowsCount; row++) {
                for(int column = 0; column < result.columnsCount; column++) {
                    result.items[row][column] = FMath.sum(a.items[row][column], b.items[row][column]);
                }
            }
        }
        else {
            //TODO make a throw: not equals constructions of matrix
            result = new Matrix(1,1);
        }

        return result;
    }

    public static Matrix multiplication(Matrix a, double number) {
        Matrix result = new Matrix(a.rowsCount, a.columnsCount);

        for(int row = 0; row < a.rowsCount; row++)
            for(int column = 0; column < a.columnsCount; column++)
                 result.items[row][column] = FMath.multiplication(number, a.items[row][column]);
        return result;
    }

    public static Matrix multiplication(Matrix a, Matrix b) {
        Matrix result;

        if(a.columnsCount == b.rowsCount) {
            result = new Matrix(a.rowsCount, b.columnsCount);

            for(int row = 0; row < result.rowsCount; row++) {
                for(int column = 0; column < result.columnsCount; column++)
                {
                    for(int inner = 0; inner < a.columnsCount; inner++) {
                        result.items[row][column] = FMath.sum(result.items[row][column],
                                FMath.multiplication(a.items[row][inner], b.items[inner][column]));
                    }
                }
            }
        }
        else {
            //TODO make a new throw: not equals first matrix columns count and second - rows count
            result = new Matrix(1, 1);
        }

        return result;
    }

    public static Matrix division(Matrix a, Fraction number) {
        //TODO make a new throw: division by zero
        //if(number == 0)

        Matrix b = new Matrix(a.rowsCount, a.columnsCount);

        for(int row = 0; row < a.rowsCount; row++)
            for(int column = 0; column < a.columnsCount; column++)
                b.items[row][column] = FMath.division(a.items[row][column], number);

        return b;
    }

    public static Matrix transpose(Matrix a) {
        Matrix b = new Matrix(a.columnsCount, a.rowsCount);

        for(int row = 0; row < a.rowsCount; row++) {
            for(int column = 0; column < a.columnsCount; column++) {
                b.items[column][row] = a.items[row][column];
            }
        }
        return b;
    }

    public static Fraction determinant(Matrix a) {
        Fraction result;

        //TODO  make a throw: not square matrix
        if(a.rowsCount != a.columnsCount) return new Fraction(0);

        if(a.rowsCount == 2) {
            result = FMath.subtraction(
                    FMath.multiplication(a.items[0][0], a.items[1][1]),
                    FMath.multiplication(a.items[0][1], a.items[1][0]));
        }
        else {
            result = new Fraction(0);
            int sign;

            for(int rowItem = 0; rowItem < a.columnsCount; rowItem++) {
                if(rowItem % 2 == 0) sign = 1; else sign = -1;

                result = FMath.sum(result,
                        FMath.multiplication(
                                FMath.multiplication(sign, a.items[0][rowItem]),
                                        determinant(a.minor(0,rowItem))));
            }
        }
        return result;
    }

    public static final Matrix inverse(Matrix a) {
        Matrix result;
        Fraction determinant = determinant(a);
        int sign;

        Matrix aT = transpose(a);

        if(determinant.doubleValue() == 0) {
            //TODO make a new throw: determinant=0, division by zero
            result = new Matrix(1,1);
        }
        else
        {
            result = new Matrix(aT.rowsCount, aT.columnsCount);

            for(int row = 0; row < result.rowsCount; row++) {
                for(int column = 0; column < result.columnsCount; column++) {
                    if((row + column)%2 == 0) sign = 1; else sign = -1;

                    result.items[row][column] =
                            FMath.multiplication(sign, determinant(aT.minor(row, column)));
                }
            }

            result = division(result, determinant);
        }

        return result;
    }

}
